package org.oimwrapper.connectors.common;

import org.oimwrapper.connectors.*;

/**
 * Updates all users of a given status to trigger group membership rules and access 
 * policy application.  This task can use threads to improve performance.<p>
 * 
 * This task expects the following parameters, in addition to the standard
 * parameters in the {@link OIMTaskBase} class.
 * <ul>
 * <li><code>Filter</code> An SQL filter to use against the user table to find users to 
 *                         touch.  The filter will be logically AND'd with the status
 *                         specified.</li>
 * <li><code>Status</code> The status of the user objects to touch.  This defaults to Active.
 *                         A wildcard can be used to retrieve all statuses.</li>
 * <li><code>Threads</code> The number of concurrent threads to run to process users in OIM.  
 *                          By default, ten submitting threads are run.</li>
 * </ul>
 */
public class OIMTouchAllUsers extends OIMTaskBase {

	/**
	 * True if a stop has been requested for this task.
	 */
	private boolean stop;
	
	/**
	 * Default constructor.
	 */
	public OIMTouchAllUsers() {
		super("OIMWRAPPER.TASK");
	}
	
	/**
	 * This method is called by the scheduler to execute the task instance.
	 */
	public void execute() {
		try {
			long[] keys = null;
			String filter = getAttribute("Filter");
			String status = getDefaultAttribute("Status", "Active");
			if (!isEmpty(filter)) {
				keys = getFilteredOimUserKeys("upper(usr_status) = upper('" + status + "') and " + filter);
			} else {
				keys = getOimUserKeys(status);
			}
			int maxWorkers = Integer.parseInt(getDefaultAttribute("Threads", "10"));
			for (int i = 0; !stop && i < keys.length; i++) {
				logger.warn("Processing User " + Integer.toString(i + 1) + " of " + Integer.toString(keys.length));
				startThread(maxWorkers, new worker(this, keys[i]));
			}
			waitForAllThreads();
		} catch (Exception e) {
			OIMExceptionHandler.handleException(logger, e, getClass());
		}
	}
	
	/**
	 * This method is called by the scheduler to stop a running task instance.
	 * 
	 * @return <code>true</code>
	 */
	public boolean stop() {
		logger.warn(" ---- Stopping current task ---- ");
		stop = true;
		return stop;
	}
	
	/**
	 * Touches a single user to invoke an update.
	 * 
	 * @param Key The key of the user to process.
	 */
	private void processSingleUser(long Key) {
		try {
			evaluatePolicies(Key);
		} catch (Exception e) {
			OIMExceptionHandler.handleException(logger, e, getClass());
		}
	}
	
	/**
	 * Worker Thread.
	 */
	private class worker extends OIMTaskThreadBase {
		
		/**
		 * The invoking task.
		 */
		private OIMTouchAllUsers task;
		
		/**
		 * The user key to process.
		 */
		private long key;
		
		/**
		 * Default Constructor.
		 * 
		 * @param Task The invoking task.
		 * @param Key The key of the user to process.
		 */
		private worker(OIMTouchAllUsers Task, long Key) {
			super(Task);
			task = Task;
			key = Key;
		}
		
		/**
		 * Processes and submits a single recon event.
		 */
		public void runOimThread() {
			task.processSingleUser(key);
		}
	}
}